use serde_json::{Value, Result};
use std::collections::HashMap;
use std::error::Error;
use std::time::Duration;
use std::thread::sleep;
use std::fs::read_to_string;
use ErrorKind;

struct DataSourceLocalFile {
    _name: str
    _path: str
}

impl DataSource for DataSourceLocalFile {
    fn new(name: str, params: Value) {
        DataSourceLocalFile {
            _name: name,
            _path: params["path"].as_str().unwrap(),
        }
    }

    fn get_name(&self) -> str {
        self._name
    }

    fn get_cache_info(&self) -> CacheInfo {
        CacheInfo {
            age: 0,
            persist: false,
        }
    }

    fn get_site_data(&self, site_list: Option<Vec<&str>>) -> HashMap<str, SiteData> {
        let mut data = HashMap::new();

        match read_to_string(&self._path) {
            Ok(contents) => {
                for line in contents.lines().map(str::trim) {
                    if line.is_empty() || line.starts_with("#") {
                        continue;
                    }
                    let items: Vec<&str> = Regex::new(r"\s+").split(s).collect()
                    let name = items[0].to_string();
                    if site_list.is_none() || site_list.as_ref().unwrap().contains(&name) {
                        if data.contains_key(&name) {
                            return Err(format!("duplicate name \"{}\" in \"{}\"", name, self.path));
                        }
                        let mirrors: Vec<String> = items[1..].iter().filter(|&x| !x.is_empty()).map(|&x| x.to_string()).collect();
                        data.insert(name, HashMap::new());
                        data.get_mut(&name).unwrap().insert("mirrors".to_string(), mirrors);
                    }
                }
                Ok(data)
            }
            Err(err) => {
                if err.kind() == ErrorKind::NotFound || err.kind() == ErrorKind::PermissionDenied {
                    Ok(data)  // Return empty result if file not found or permission denied
                } else if err.kind() == ErrorKind::InvalidInput {
                    Err(format!("\"{}\" is a directory", self.path))  // Raise error if the target path is a directory
                } else {
                    Err(err.to_string())  // Raise error for other IO errors
                }
            }
        }
    }
}